package xin.homeant.framework.httpclient;


import java.io.File;

import java.io.IOException;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import xin.homeant.framework.httpclient.jdk.JDKHttpClient;
import xin.homeant.framework.httpclient.jdk.JDKHttpClientConfig;
import xin.homeant.framework.httpclient.model.HttpAsyncRequestCallback;
import xin.homeant.framework.httpclient.model.HttpConfig;
import xin.homeant.framework.httpclient.model.HttpRequest;
import xin.homeant.framework.httpclient.model.HttpResponse;

/**
 * <P>
 * http服务类
 * </P>
 * 
 * @author homeant homeanter@163.com
 * @Data 2017年5月20日 下午1:50:47
 */
public class HttpService implements AutoCloseable {

    private final HttpConfig config;
    private final HttpClient httpClient;

    public HttpService(HttpConfig config) {
        this.config = config;
        final HttpClientConfig httpClientConfig = config.getHttpClientConfig();
        final HttpClient externalHttpClient = config.getHttpClient();

        if (httpClientConfig == null && externalHttpClient == null) {
            httpClient = new JDKHttpClient(JDKHttpClientConfig.defaultConfig());
        } else {
            httpClient = externalHttpClient == null ? getClient(httpClientConfig) : externalHttpClient;
        }
    }

    private static HttpClient getClient(HttpClientConfig config) {
        for (HttpClientProvider provider : ServiceLoader.load(HttpClientProvider.class)) {
            final HttpClient client = provider.createClient(config);
            if (client != null) {
                return client;
            }
        }
        return null;
    }

    @Override
    public void close() throws IOException {
        httpClient.close();
    }

    public HttpConfig getConfig() {
        return config;
    }

    public Future<HttpResponse> executeAsync(HttpRequest request) {
        return execute(request, null);
    }

    public Future<HttpResponse> execute(HttpRequest request, HttpAsyncRequestCallback<HttpResponse> callback) {
        return execute(request, callback, null);
    }

    public <R> Future<R> execute(HttpRequest request, HttpAsyncRequestCallback<R> callback,HttpRequest.ResponseConverter<R> converter) {

        final File filePayload = request.getFilePayload();
        if (filePayload != null) {
            return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
                    request.getCompleteUrl(), filePayload, callback, converter);
        } else if (request.getStringPayload() != null) {
            return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
                    request.getCompleteUrl(), request.getStringPayload(), callback, converter);
        } else {
            return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
                    request.getCompleteUrl(), request.getByteArrayPayload(), callback, converter);
        }
    }

    public HttpResponse execute(HttpRequest request) throws InterruptedException, ExecutionException, IOException {
        final File filePayload = request.getFilePayload();
        if (filePayload != null) {
            return httpClient.execute(config.getUserAgent(), request.getHeaders(), request.getVerb(),
                    request.getCompleteUrl(), filePayload);
        } else if (request.getStringPayload() != null) {
            return httpClient.execute(config.getUserAgent(), request.getHeaders(), request.getVerb(),
                    request.getCompleteUrl(), request.getStringPayload());
        } else {
            return httpClient.execute(config.getUserAgent(), request.getHeaders(), request.getVerb(),
                    request.getCompleteUrl(), request.getByteArrayPayload());
        }
    }
}
